#include "pic.h"

#include "bt.h"
#include "hc05.h"
#include "kb.h"
#include "oled.h"
#include "sel.h"
#include "show.h"
#include "usart.h"
#include "ws2812.h"

#undef Handler
#define Handler Pic_HandleTypeDef*

#undef handler
#define handler (**(Pic_HandleTypeDef**)&handle)

void Pic_Init(void* handle) {
  Oled_ClearAll();
  Oled_ShowStringBig(0, 0, "    PICTURES    ");
  handler.mode = PIC_BEGIN;
  handler.highest = 0;
  handler.selected = 0;
  // 初始化所有图片的文件名
  for (uint8_t i = 0; i < 32; i++) {
    uint8_t j;
    Matrix** tmp;  //
    for (j = 0; j < 16; j++) {
      // 为了消除强制类型转换的编译警告, 必须引入一个临时变量
      tmp = (Matrix**)&Ws_addrList[i];
      if ((*tmp)->name[j] == '\0') break;
    }
    if (j == 16) {
      // name中所有byte都不是'\0', 说明此图片还未初始化,
      // 否则图片名的末尾必有一个'\0'
      Flash_Erase(Ws_addrList[i]);
      Flash_Write(Ws_addrList[i], (uint16_t*)"\0", 8);
    }
  }
  Pic_Reinit(handle);
}

void Pic_Reinit(void* handle) {
  // 初始化bt
  Bt_Init(Pic_M_L, NULL, NULL, Pic_M_O,           // M
          Pic_U_LWO, Pic_U_LWO, NULL, Pic_U_LWO,  // U
          Pic_D_LWO, Pic_D_LWO, NULL, Pic_D_LWO,  // D
          Pic_L_LW, Pic_L_LW, NULL, Pic_L_O,      // L
          Pic_R_LW, Pic_R_LW, NULL, Pic_R_O,      // R
          150);
  // 初始化oled
  Oled_ClearAll();
  // 初始化pic
  handler.into = 0;
  handler.outo = 0;
  Pic_InitShow(handle);
  Pic_ShowMode(handle);
  Ws_Read(handler.highest + handler.selected);
  Ws_Load(hws.matrix.color);
  Ws_Draw();
  // 死循环, 直到所有按键松开
  while (hbt.bu & BU_M) Bt_Update();
}

void Pic_InitShow(void* handle) {
  turn = 0xFF;
  Oled_ShowStringBig(0, 0, "    PICTURES    ");
  turn = 0x00;
  Pic_ShowSelected(handle);
  Oled_ShowStringSmall(0, 5, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80");
  Oled_ShowStringSmall(64, 5, "\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80\x80");
  Oled_ShowStringBig(0, 6, "|<|          |>|");
  Pic_ShowMode(handle);
}

void Pic_ShowSelected(void* handle) {
  // 此函数先显示要显示的图片名, 再擦除剩余部分的屏幕, 以此防止刷新时闪烁
  Matrix** tmp = (Matrix**)&Ws_addrList[handler.highest];
  uint8_t k1 = 0, k2 = 0, k3 = 0;
  while ((*tmp)->name[k1] != '\0') k1++;
  turn = (handler.selected == 0) ? 0xFF : 0x00;
  Oled_ShowNumSmall(0, 2, handler.highest + 1, 2);
  Oled_ShowCharSmall(12, 2, ' ');
  Oled_ShowStringSmall(18, 2, (char*)(*tmp)->name);
  tmp = (Matrix**)&Ws_addrList[handler.highest + 1];
  while ((*tmp)->name[k2] != '\0') k2++;
  turn = (handler.selected == 1) ? 0xFF : 0x00;
  Oled_ShowNumSmall(0, 3, handler.highest + 2, 2);
  Oled_ShowCharSmall(12, 3, ' ');
  Oled_ShowStringSmall(18, 3, (char*)(*tmp)->name);
  tmp = (Matrix**)&Ws_addrList[handler.highest + 2];
  while ((*tmp)->name[k3] != '\0') k3++;
  turn = (handler.selected == 2) ? 0xFF : 0x00;
  Oled_ShowNumSmall(0, 4, handler.highest + 3, 2);
  Oled_ShowCharSmall(12, 4, ' ');
  Oled_ShowStringSmall(18, 4, (char*)(*tmp)->name);
  turn = 0x00;
  uint8_t str[] = "               ";
  str[15 - k1] = '\0';
  Oled_ShowStringSmall(18 + k1 * 6, 2, (char*)str);
  str[15 - k1] = ' ';
  str[15 - k2] = '\0';
  Oled_ShowStringSmall(18 + k2 * 6, 3, (char*)str);
  str[15 - k1] = ' ';
  str[15 - k3] = '\0';
  Oled_ShowStringSmall(18 + k3 * 6, 4, (char*)str);
  str[15 - k3] = ' ';
}

void Pic_ShowMode(void* handle) {
  switch (handler.mode) {
    case PIC_SHOW:
      Oled_ShowStringBig(24, 6, "   show   ");
      break;
    case PIC_SEL:
      Oled_ShowStringBig(24, 6, "   edit   ");
      break;
    case PIC_IMPORT:
      Oled_ShowStringBig(24, 6, "  import  ");
      break;
    case PIC_EXPORT:
      Oled_ShowStringBig(24, 6, "  export  ");
      break;
    case PIC_RENAME:
      Oled_ShowStringBig(24, 6, "  rename  ");
  }
}

void Pic_Run(void* handle) {
  uint32_t timeroll = 0;
  while (1) {
    Bt_Update();
    Bt_Run(handle);
    if (handler.mode == PIC_SHOW) {
      if (hbt.time.now - timeroll > 300) {
        timeroll = hbt.time.now;
        hws.offset++;
        Ws_Load(hws.matrix.color);
        Ws_Draw();
      }
    } else {
      hws.offset = 0;
      Ws_Load(hws.matrix.color);
      Ws_Draw();
    }

    if (handler.into == 1) {
      handler.into = 0;
      switch (handler.mode) {
        case PIC_SHOW: {
          Ws_Read(handler.highest + handler.selected);
          Show_HandleTypeDef hpic;
          Show_Init(&hpic);
          Show_Run(&hpic);
          // 还原图片偏置和方向
          hws.offset = 0;
          hws.reserve = 0;
          Ws_Load(hws.matrix.color);
          Ws_Draw();
        } break;
        case PIC_SEL: {
          Ws_Read(handler.highest + handler.selected);
          Sel_HandleTypeDef hsel;
          Sel_Init(&hsel, handler.highest + handler.selected);
          Sel_Run(&hsel);
          // 在此处保存修改到flash
          if (hsel.save) {
            Ws_Save(handler.highest + handler.selected);
          }
        } break;
        case PIC_IMPORT: {
          Oled_ClearAll();
          turn = 0xFF;
          Oled_ShowStringBig(0, 0, "     IMPORT     ");
          turn = 0x00;
          Ws_Read(handler.highest + handler.selected);
          for (uint16_t k = 0; k < 1024; k++) {
            hhc.matrix[k] = ((uint8_t*)(&hws.matrix))[k];
          }
          Oled_ShowStringSmall(0, 2, "Recieving...");
          hhc.mode = 1;
          while (hhc.mode || (hbt.bu & BU_M) == BU_M_M) {
            Oled_ShowNumSmall(0, 7, hhc.idx, 4);
            Bt_Update();
          }
          Oled_ShowStringSmall(0, 3, "Complete!");
          for (uint16_t k = 0; k < 1024; k++) {
            ((uint8_t*)(&hws.matrix))[k] = hhc.matrix[k];
          }
          Ws_Save(handler.highest + handler.selected);
          Ws_Load(hws.matrix.color);
          Ws_Draw();
        } break;
        case PIC_EXPORT: {
          Oled_ClearAll();
          turn = 0xFF;
          Oled_ShowStringBig(0, 0, "     EXPORT     ");
          turn = 0x00;
          Matrix** tmp =
              (Matrix**)&Ws_addrList[handler.highest + handler.selected];
          Ws_Load((*tmp)->color);
          Ws_Draw();
          Oled_ShowStringSmall(0, 2, "Delieving...");
          for (uint16_t k = 0; k < 1024; k++) {
            HAL_UART_Transmit(&huart1, (uint8_t*)(*tmp) + k, 1, 0xFFFF);
            Oled_ShowNumSmall(0, 7, k, 4);
            HAL_Delay(2);
          }
          Oled_ShowStringSmall(0, 3, "Complete!");
        } break;
        case PIC_RENAME: {
          Kb_HandleTypeDef hkb;
          Matrix** tmp =
              (Matrix**)&Ws_addrList[handler.highest + handler.selected];
          Kb_Init(&hkb, (char*)(*tmp)->name);
          Kb_Run(&hkb);
          if (hkb.save) {
            Ws_Read(handler.highest + handler.selected);
            for (uint8_t i = 0; i < 16; i++) {
              hws.matrix.name[i] = hkb.str[i];
            }
            Ws_Save(handler.highest + handler.selected);
          }
        }
      }

      Pic_Reinit(handle);
    }
    if (handler.outo) {
      return;
    }
  }
}
void Pic_M_L(void* handle) { handler.outo = 1; }
void Pic_M_O(void* handle) { handler.into = 1; }

void Pic_U_LWO(void* handle) {
  if (!(hbt.bu & BU_S_U) && hbt.hist) return;

  if (handler.selected == 0) {
    if (handler.highest == 0) {
      handler.highest = 29;
      handler.selected = 2;
    } else {
      handler.highest--;
    }
  } else {
    handler.selected--;
  }
  Pic_ShowSelected(handle);
  Ws_Read(handler.highest + handler.selected);
  Ws_Load(hws.matrix.color);
  Ws_Draw();
}
void Pic_D_LWO(void* handle) {
  if (!(hbt.bu & BU_S_D) && hbt.hist) return;

  if (handler.selected == 2) {
    if (handler.highest == 29) {
      handler.highest = 0;
      handler.selected = 0;
    } else {
      handler.highest++;
    }
  } else {
    handler.selected++;
  }
  Pic_ShowSelected(handle);
  Ws_Read(handler.highest + handler.selected);
  Ws_Load(hws.matrix.color);
  Ws_Draw();
}
void Pic_L_LW(void* handle) {
  if (handler.mode == PIC_BEGIN) {
    handler.mode = PIC_END;
  } else {
    handler.mode--;
  }
  turn = 0xFF;
  Oled_ShowCharBig(8, 6, '<');
  turn = 0x00;
  Pic_ShowMode(handle);
}
void Pic_R_LW(void* handle) {
  if (handler.mode == PIC_END) {
    handler.mode = PIC_BEGIN;
  } else {
    handler.mode++;
  }
  turn = 0xFF;
  Oled_ShowCharBig(112, 6, '>');
  turn = 0x00;
  Pic_ShowMode(handle);
}

void Pic_L_O(void* handle) {
  if (!hbt.hist) Pic_L_LW(handle);
  Oled_ShowCharBig(8, 6, '<');
}
void Pic_R_O(void* handle) {
  if (!hbt.hist) Pic_R_LW(handle);
  Oled_ShowCharBig(112, 6, '>');
}
